package com.du.web.sample.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.reader.SheetReader;
import com.alibaba.fastjson.JSON;
import com.du.web.sample.mapper.GisDataMapper;
import com.du.web.sample.mapper.GisFirmMapper;
import com.du.web.sample.mapper.LearnTaskMapper;
import com.du.web.sample.model.GisData;
import com.du.web.sample.model.GisFirm;
import com.du.web.sample.model.ResBean;
import com.du.web.sample.model.content.PutContent;
import com.du.web.sample.model.gateway.ApiEntity;
import com.du.web.sample.model.gateway.GatewayApiData;
import com.du.web.sample.model.gateway.GroupEntity;
import com.du.web.sample.model.learn.LearnStatistics;
import com.du.web.sample.model.learn.LearnTaskData;
import com.du.web.sample.model.learn.LearnTaskDataDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @desc:
 * @author: shuangdu
 * @date: 2021/9/13
 * @since: 1.8
 */
@RestController
@RequestMapping(path = "index")
@Slf4j
@RequiredArgsConstructor
public class IndexController {

    private final GisDataMapper gisDataMapper;

    private final GisFirmMapper gisFirmMapper;

    private final LearnTaskMapper learnTaskMapper;


    @GetMapping("/dict")
    public void exportDict(HttpServletResponse response) throws Exception {
        String rootName = "xxx-" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        response.setContentType("application/zip");
        
        // 对文件名进行URL编码，解决HTTP头中不能包含Unicode字符的问题
        String encodedFileName;
        try {
            encodedFileName = URLEncoder.encode(rootName + ".zip", StandardCharsets.UTF_8.toString());
        } catch (UnsupportedEncodingException e) {
            encodedFileName = rootName + ".zip";
        }
        response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");

        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ZipOutputStream zos = new ZipOutputStream(baos)) {

            // 假设有数据
            String fileName = "xxx_zh.json";
            String content = "{\"key\":\"value\"}"; // 这里用实际内容替换

            zos.putNextEntry(new ZipEntry(rootName + "/xxx/" + fileName));
            zos.write(content.getBytes(StandardCharsets.UTF_8));
            zos.closeEntry();

            zos.finish(); // 可选
            response.getOutputStream().write(baos.toByteArray());
            response.getOutputStream().flush();
        }
    }

    /**
     *
     * 导入数据
     * @param file
     * @return
     */
    @PostMapping(path = "gis")
    public ResBean importGisData(@RequestParam(value = "file") MultipartFile file) {
        try {
            ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
            List<GisData> gisData = reader.readAll(GisData.class);
            // 写库
            gisData.forEach(gisDataMapper::insert);
            return ResBean.ok();
        } catch (IOException e) {
            return ResBean.error(e.getMessage());
        }
    }

    @PostMapping(path = "firm")
    public ResBean importGisFirmData(@RequestParam(value = "file") MultipartFile file) {
        try {
            ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
            List<GisFirm> gisData = reader.readAll(GisFirm.class);
            // 写库
            gisData.forEach(gisFirmMapper::insert);
            return ResBean.ok();
        } catch (IOException e) {
            return ResBean.error(e.getMessage());
        }
    }

    @PostMapping(path = "statistics")
    public ResBean importStatisticsData(@RequestParam(value = "file") MultipartFile file) {
        try {
            ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
            List<LearnStatistics> data = reader.readAll(LearnStatistics.class);
            Map<String, Integer> map = new HashMap<>();
            data.forEach(i -> {
                String str = i.getStr();
                if (Pattern.matches("\\| [0-9]{4}-[0-9]{2} \\| [0-9 ]*\\|", str)) {
                    String[] s = str.split("\\|");
                    String month = s[1].trim();
                    int num = Integer.valueOf(s[2].trim());
                    map.merge(month, num, (v1, v2) -> v1 + v2 );
                }
            });
            return ResBean.ok(map);
        } catch (IOException e) {
            return ResBean.error(e.getMessage());
        }
    }

    @PostMapping(path = "learnTask")
    public ResBean importLearnTaskData(@RequestParam(value = "file") MultipartFile file, @RequestParam(value = "uFile") MultipartFile uFile) {
        BufferedReader br = null;
        InputStreamReader isr = null;
        try {
            isr = new InputStreamReader(uFile.getInputStream());
            br = new BufferedReader(isr);
            HashSet<String> uid = new HashSet<>();
            String temp = null;
            while ((temp = br.readLine()) != null) {
                uid.add(temp.trim());
            }

            log.info("uid读取完成!");
            ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
            List<LearnTaskDataDTO> learnData = reader.readAll(LearnTaskDataDTO.class);
            // 写库
            Date now = new Date();
            learnData.forEach(data -> {
                if (data.getUserId() != null && uid.contains(data.getUserId())) {
                    // userId查询记录，不存在则新增
                    LearnTaskData taskData = learnTaskMapper.selectById(data.getUserId());
                    if (taskData != null) {
                        // 原学校
                        if (!hasSchoolId(taskData.getSchoolIds(), data.getSourceSchoolId())) {
                            taskData.setSchoolIds(concatSchoolId(taskData.getSchoolIds(), data.getSourceSchoolId()));
                        }
                        // 目标学校
                        if (!hasSchoolId(taskData.getSchoolIds(), data.getTargetSchoolId())) {
                            taskData.setSchoolIds(concatSchoolId(taskData.getSchoolIds(), data.getTargetSchoolId()));
                        }
                        taskData.setModifyTime(now);
                        learnTaskMapper.updateById(taskData);

                    } else {
                        // 新增 记录
                        taskData = new LearnTaskData();
                        taskData.setUserId(data.getUserId());
                        taskData.setUserName(data.getUserName());
                        taskData.setSchoolIds(concatSchoolId(data.getSourceSchoolId(), data.getTargetSchoolId()));
                        taskData.setCreateTime(now);
                        learnTaskMapper.insert(taskData);
                    }
                }
            });
            return ResBean.ok();
        } catch (IOException e) {
            return ResBean.error(e.getMessage());
        } finally {
            if (isr != null) {
                try {
                    isr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private boolean hasSchoolId(String schoolIds, String id) {
        String[] split = schoolIds.split(",");
        return Arrays.asList(split).contains(id);
    }

    private String concatSchoolId(String source, String target) {
        if (StrUtil.isNotBlank(source) && !source.equals("0")) {
            if (StrUtil.isNotBlank(target) && !target.equals("0")) {
                // 都不为空，拼接
                return source.concat(",").concat(target);
            } else {
                return source;
            }
        } else {
            if (StrUtil.isNotBlank(target)) {
                return target;
            }
        }
        // 都为空
        return "";
    }


    @PostMapping(path = "apiData")
    public void importApiData(@RequestParam(value = "file") MultipartFile file, HttpServletResponse response) {
        try {
            InputStream is = file.getInputStream();
            InputStreamReader isReader = new InputStreamReader(is, StandardCharsets.UTF_8);
            BufferedReader fileReader = new BufferedReader(isReader);
            StringBuilder sb = new StringBuilder();
            while (fileReader.ready()) {
                sb.append(fileReader.readLine());
            }

            fileReader.close();
            GatewayApiData data = JSON.parseObject(sb.toString(), GatewayApiData.class);

            ExcelWriter writer = ExcelUtil.getWriter(true);
            List<GroupEntity> list = data.getGroupEntityList();
            for (GroupEntity entity : list) {
                List<ApiEntity> apiEntityList = entity.getApiEntityList();
                for (ApiEntity apiEntity : apiEntityList) {
                    writer.writeRow(apiEntity.getApiBaseEntity(), false);
                }
            }

            String fileName = file.getOriginalFilename().substring(0, Objects.requireNonNull(file.getOriginalFilename()).lastIndexOf("."));
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            
            // 对中文文件名进行URL编码，解决HTTP头中不能包含Unicode字符的问题
            String encodedFileName;
            try {
                encodedFileName = URLEncoder.encode(fileName + ".xlsx", StandardCharsets.UTF_8.toString());
            } catch (UnsupportedEncodingException e) {
                encodedFileName = fileName + ".xlsx";
            }
            response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");
            ServletOutputStream out = response.getOutputStream();

            writer.flush(out, true);
            writer.close();
            IoUtil.close(out);
        } catch (IOException e) {
        }
    }

    @PostMapping(path = "content")
    public ResBean importContent(@RequestParam(value = "file") MultipartFile file) {
        try {
            ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
            List<PutContent> data = reader.readAll(PutContent.class);
            StringBuilder sb = new StringBuilder();
            data.forEach(i -> {
                String[] contentIds = i.getContentIds().split(",");
                for (String contentId : contentIds) {
                    String temp = "INSERT INTO put_classification_content_info(content_id, association_id, association_type, create_time, update_time, is_delete)VALUES(%s, %s, %s, '%s', '%s', %s);";
                    sb.append(
                            String.format(
                                    temp,
                                    contentId,
                                    i.getAssociationId(),
                                    1,
                                    i.getCreateTime(),
                                    i.getUpdateTime(),
                                    i.getIsDelete()
                            )
                    );
                }
            });
            return ResBean.ok(sb);
        } catch (IOException e) {
            return ResBean.error(e.getMessage());
        }
    }

    @PostMapping(path = "test")
    public ResBean test(String userName, Integer userAge) throws Exception {
        log.info("{}, {}", userName, userAge);
        CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> fetchXhr());
        CompletableFuture<Double> future = CompletableFuture.supplyAsync(() -> fetchXhr())
                .thenCombineAsync(future1, (random1, random2) -> {
                    log.info("返回参数：{} {}", random1, random2);
                    return (double)random1 + (double)random2;
                })
                .exceptionally((e) -> {
                    log.error("异常了: {}", e.getMessage());
                    return null;
                });
        return ResBean.ok(future.get());
    }

    static Random random = new Random();
    public static Object fetchXhr() {
        double d = random.nextDouble();
        if (d < 0.1) {
            throw new IllegalStateException("mock exception");
        }
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return d;
    }
}
